package algorithm;

import java.util.Random;

/**
 * 排序辅助类
 */
public class SortHelper {

    /**
     * 交换数组中两个元素的位置
     *
     * @param arr 数组
     * @param i   第一个元素位置
     * @param j   第二个元素位置
     * @param <T> 泛型
     */
    public static <T extends Comparable> void swap(T[] arr, int i, int j) {
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
     * 生产一个指定长度的且每个元素大小在指定范围内的整形数组
     *
     * @param length 长度
     * @param rangeL 最小值
     * @param rangeH 最大值
     * @return 一个指定长度的且每个元素大小在指定范围内的整形数组
     */
    public static Integer[] generateRandomArray(int length, Integer rangeL, Integer rangeH) {

        assertTrue("最小值必须小于等于最大值", rangeL <= rangeH);

        Integer[] arr = new Integer[length];
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            arr[i] = random.nextInt(rangeH) % (rangeH - rangeL + 1) + rangeL;
        }

        return arr;
    }

    /**
     * 生产一个指定长度且近似已经排序的整形数组
     *
     * @param length    长度
     * @param swapTimes 交换次数
     * @return 一个指定长度且近似已经排序的整形数组
     */
    public static Integer[] generateNearlyOrderedArray(int length, int swapTimes) {
        Integer[] arr = new Integer[length];
        for (int i = 0; i < length; i++) {
            arr[i] = i;
        }
        Random random = new Random();
        for (int i = 0; i < swapTimes; i++) {
            int posx = random.nextInt(length);
            int posy = random.nextInt(length);
            swap(arr, posx, posy);
        }
        return arr;
    }

    /**
     * 打印数组
     *
     * @param arr 数组
     * @param <T> 泛型
     */
    public static <T> void printArray(T[] arr) {
        int n = arr.length > 100 ? 100 : arr.length;
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    /**
     * 测试排序算法, 打印耗时等信息
     *
     * @param sortName 算法名称
     * @param sort     算法实现
     * @param arr      数组
     * @param <T>      泛型
     */
    public static <T extends Comparable> void testSort(String sortName, Sort sort, T[] arr) {
        //开始时间
        long startTime = System.nanoTime();
        //排序
        sort.sort(arr);
        //结束时间
        long endTime = System.nanoTime();
        //校验是否排序完成
        assertTrue("数组没有排序", isSorted(arr));

        System.out.println(sortName + " : " + (endTime - startTime) / 1000000.0 + " ms");
        printArray(arr);
    }

    /**
     * 校验数组是否已经排序, 默认升序
     *
     * @param arr 数组
     * @param <T> 泛型
     * @return 是否已经排序
     */
    public static <T extends Comparable> boolean isSorted(T[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i].compareTo(arr[i + 1]) > 0) {
                printArray(arr);
                return false;
            }
        }
        return true;
    }

    public static <T extends Comparable> boolean less(T t1, T t2) {
        return t1.compareTo(t2) < 0;
    }

    private static void assertTrue(boolean condition) {
        if (!condition) {
            throw new Error();
        }
    }

    private static void assertTrue(String message, boolean condition) {
        if (!condition) {
            throw new Error(message);
        }
    }


}
